home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d2 / zapscrn.arc / ZAP.ASM < prev    next >
Assembly Source File  |  1989-03-11  |  18KB  |  586 lines

  1.  
  2. page 60,132
  3.  
  4. ; Copyright (C) 1988  Mark Adler  Pasadena, CA
  5. ; All rights reserved.
  6.  
  7.  title ZAP - screen saver for the EGA or VGA
  8.  
  9. comment #
  10.  
  11. Version history -
  12.  
  13. 1.0     18 Nov 1988     First public version
  14. 1.1     14 Dec 1988     Fixed bug in EGAZAP
  15.  
  16.  
  17. ZAP -
  18.  
  19.  ZAP is a resident utility that blanks the screen after a specified
  20.  period of inactivity.  The ZAP.ASM program actually generates two
  21.  different programs depending on the assembler options:  EGAZAP and
  22.  VGAZAP.  The first is for the IBM Enhanced Graphics Adapter or
  23.  compatibles, and the second is for IBM PS/2's, the IBM Video Graphics
  24.  Adpater, and comaptibles.  From here on, ZAP will be used to mean
  25.  EGAZAP or VGAZAP, whichever is appropriate for your hardware.
  26.  
  27.  To install ZAP, simply put the command ZAP in your AUTOEXEC.BAT file.
  28.  From then on, when there is five minutes of inactivity at the
  29.  keyboard, ZAP will blank the screen until any key (even just a shift
  30.  key) is hit.  The time can be changed with a command line option which
  31.  specifies the time in seconds.  For example:
  32.  
  33.      zap 600
  34.  
  35.  will install ZAP (if not already installed) and change the time to 10
  36.  minutes.
  37.  
  38.  You can also turn the installed ZAP on and off using ZAP.  For example:
  39.  
  40.      zap off
  41.  
  42.  will turn off the installed ZAP, so it will not blank the screen.  Then
  43.  the command:
  44.  
  45.      zap on
  46.  
  47.  will turn ZAP back on.
  48.  
  49.  ZAP can also be installed in the "off" state, awaiting a "zap on"
  50.  command, simply by using:
  51.  
  52.      zap off
  53.  
  54.  in AUTOEXEC.BAT.  You can also specify on or off along with a new
  55.  inactivity time.  For example, the command:
  56.  
  57.      zap off 600
  58.  
  59.  in AUTOEXEC.BAT will install ZAP in the off state with a 10 minute
  60.  inactivity time.  Then a subsequent "zap on" will turn it on.  The time
  61.  must be in the range of one to 3600 seconds (one hour).  Specifying a
  62.  new time does not change whether ZAP is enabled or not and turning ZAP
  63.  on or off does not change the time.  Also, the two options can be in
  64.  either order.  For example, "zap 600 off" does the same thing as the
  65.  example above.  If ZAP is already installed, subsequent invocations of
  66.  ZAP will not install it again.  If the command:
  67.  
  68.      zap
  69.  
  70.  is entered after ZAP is already installed, this has the same effect as
  71.  the command "zap on", that is it turns on ZAP if it was off.
  72.  
  73.  ZAP turns the display back on not only when any key is hit, but also if
  74.  any video BIOS calls (int 10h) are made.  Since most application
  75.  programs seem to bypass the BIOS for video, this added feature has
  76.  little effect.
  77.  
  78.  There are a few, rare programs that also completely take the keyboard
  79.  from the BIOS, in which case ZAP can no longer find out when keystrokes
  80.  occur.  An example is STSC APL (a programming language).  In this case,
  81.  ZAP will blank your display, even though you have been merrily typing
  82.  away for the last five minutes in the application.  And the only way to
  83.  get the display back on is to return to DOS (assuming you can get out
  84.  while driving the application blindfolded).  For such applications, you
  85.  should include the commands "zap off" and "zap on" in a batch file that
  86.  runs the application to disable ZAP before entering and enabling ZAP
  87.  after leaving the application.  You will quickly discover if you have
  88.  any such applications.
  89.  
  90.  This program assumes that the current display is the (only) active
  91.  display, but does not check for it either at installation or when
  92.  running.
  93.  
  94.  For the EGA, the screen is blanked by setting the number of characters
  95.  displayed to one, and the start of horizontal blanking to the first
  96.  character.  The number of displayed characters needs to be small (set
  97.  to one for convenience) since the horizontal blanking interval is
  98.  limited to 32 characters.  The screen is restored by getting the
  99.  current screen mode information from the BIOS and from that and the
  100.  table of Start Horizontal Blanking values in this program (copied from
  101.  the BIOS listing---not entirely kosher, but the only decent approach),
  102.  the proper register values are restored.
  103.  
  104.  For the VGA, the screen is blanked and restored using the Screen Off
  105.  bit in the Clocking Mode Register (port 0x3c4, address 01, bit 5).
  106.  
  107.  To minimize the resident memory required, this program is assembled
  108.  separately for the EGA or VGA.  When assembling, define the symbol EGA
  109.  or VGA in the command line using /d (see the manual for MASM or TASM).
  110.  If no symbol is defined, you will be warned and the resulting .COM file
  111.  will be asssembled for the VGA.  For example, the commands:
  112.  
  113.      tasm /dega zap
  114.      tlink /t zap,egazap
  115.      tasm /dvga zap
  116.      tlink /t zap,vgazap
  117.  
  118.  will generate EGAZAP.COM and VGAZAP.COM, assuming that you have the
  119.  Borland Turbo Assembler.
  120.  
  121.  The fact that the number of bytes in VGAZAP (666) is the same as
  122.  Reagan's retirement home's address in Bel Air should be given no
  123.  religious significance.
  124.  
  125. #
  126.  
  127. ifndef VGA
  128. ifndef EGA
  129.  %out !No display specified---assembling for the VGA.
  130. endif
  131. endif
  132.  
  133. ;
  134. ; Macros for blanking screens.
  135. ;
  136.  
  137. egaoff macro
  138.  local ismono,CRTMON,CRTCOL
  139. CRTMON equ 03B4h        ;;CRT controller register in Mono mode.
  140. CRTCOL equ 03D4h        ;;CRT controller register in Color mode.
  141.   push AX               ;;Save registers.
  142.   push BX
  143.   push CX
  144.   push DX
  145.   mov AH,12h            ;;Get Mono/Color in BH.
  146.   mov BL,10h
  147.   pushf                 ;;Do Int 10h
  148.   push CS
  149.   call altvid
  150.   mov DX,CRTMON         ;;Point DX to CRT port in Mono mode.
  151.   test BH,BH            ;;See if color mode.
  152.   jnz ismono            ;;If not, then DX is correct.
  153.    mov DX,CRTCOL        ;;If color, use color address.
  154.  ismono:
  155.   mov AX,1              ;;Set number of characters to 1.
  156.   out DX,AX
  157.   inc AX                ;;Set horizontal start of blanking to char 0.
  158.   out DX,AX
  159.   pop DX                ;;Restore registers.
  160.   pop CX
  161.   pop BX
  162.   pop AX
  163. endm
  164.  
  165. egaon macro
  166.  local ismono,enhance,shbget,tbl,CRTMON,CRTCOL
  167. CRTMON equ 03B4h        ;;CRT controller register in Mono mode.
  168. CRTCOL equ 03D4h        ;;CRT controller register in Color mode.
  169. ;;
  170. ;; Restore the display by getting the correct register values and
  171. ;; setting them.
  172. ;;
  173.         ;; save registers used by routine, except AX.
  174.   push BX
  175.   push CX
  176.   push DX
  177.         ;; get CRT port, switch setting.
  178.   mov AH,12h            ;;Get switch setting into CL, Mono/Color in BH.
  179.   mov BL,10h
  180.   pushf                 ;;Do Int 10h
  181.   push CS
  182.   call altvid
  183.   mov DX,CRTMON         ;;Point DX to CRT port in Mono mode.
  184.   test BH,BH            ;;See if color mode.
  185.   jnz ismono            ;;If not, then DX is correct.
  186.    mov DX,CRTCOL        ;;If color, use color address.
  187.  ismono:
  188.         ;; get values for CRT registers 1 and 2.
  189.   mov AH,0Fh            ;;Get mode into AL, columns into AH.
  190.   pushf                 ;;Do Int 10h
  191.   push CS
  192.   call altvid
  193.   dec AH                ;;Compute Horizontal Display End setting (1).
  194.   cmp AL,3              ;;See if color mode.
  195.   ja shbget             ;;If not, go on to get Start Horiz Blank (2).
  196.    cmp CL,3             ;;See if in secondary enhanced mode.
  197.    je enhance           ;;If so, use enhanced 0-3 settings.
  198.     cmp CL,9            ;;See if in primary enhanced mode.
  199.     jne shbget          ;;If not, use normal 0-3 settings.
  200.    enhance:
  201.      add AL,11h         ;;Add offset for table.
  202.  shbget:
  203.   mov BX,(offset trap)+(tbl-set)        ;;Point to table.
  204.   xlat byte ptr CS:tbl  ;;Get Start Horizontal Blank setting.
  205.         ;; Now AH is CRT register 1, AL is register 2 - set them.
  206.   mov CL,AL             ;;Save register 2 setting.
  207.   mov AL,1              ;;Set register 1.
  208.   out DX,AX
  209.   mov AH,CL             ;;Get register 2 setting.
  210.   inc AX                ;;Set register 2.
  211.   out DX,AX
  212.         ;; done, restore registers and return.
  213.   pop DX
  214.   pop CX
  215.   pop BX
  216.   ret
  217.         ;;Start horiz blank values for modes 0-10, 0*-3*.
  218.  tbl label byte
  219.   db 2Dh,2Dh,5Ch,5Ch,2Dh,2Dh,59h,56h            ;;0-7.
  220.   db 2Dh,2Dh,2Dh,5Ch,56h,2Dh,59h,56h,53h        ;;8-10h.
  221.   db 2Bh,2Bh,53h,53h                            ;;0*-3*.
  222. endm
  223.  
  224. vgaoff macro
  225.  local CRTSEQ
  226. CRTSEQ equ 03C4h        ;;CRT Sequencer register set.
  227.   push AX               ;;Save registers.
  228.   push DX
  229.   mov DX,CRTSeq         ;;Sequencer registers.
  230.   mov AL,1              ;;Point to Clocking Mode register.
  231.   out DX,AL
  232.   inc DX
  233.   in AL,DX              ;;Get current value.
  234.   or AL,020h            ;;Turn on Screen Off bit.
  235.   out DX,AL
  236.   pop DX                ;;Restore registers.
  237.   pop AX
  238. endm
  239.  
  240. vgaon macro
  241.  local CRTSEQ
  242. CRTSEQ equ 03C4h        ;;CRT Sequencer register set.
  243.         ;; save registers used by routine, except AX.
  244.   push DX
  245.         ;; turn Screen Off bit off.
  246.   mov DX,CRTSEQ         ;;Sequencer registers.
  247.   mov AL,1              ;;Point to Clocking Mode register.
  248.   out DX,AL
  249.   inc DX
  250.   in AL,DX              ;;Get current value.
  251.   and AL,0DFh           ;;Turn off Screen Off bit.
  252.   out DX,AL
  253.         ;; done, restore registers and return.
  254.   pop DX
  255.   ret
  256. endm
  257.  
  258.  
  259. ;
  260. ; Interrupt vector segment definitions.
  261. ;
  262.  
  263. ints segment at 0
  264. dummy label far
  265.  org 8*4                ;Point to Int 8 (tick) vector.
  266. int8 label word
  267.  org 9*4                ;Point to Int 9 (scan) vector.
  268. int9 label word
  269.  org 10h*4              ;Point to Int 10h (video) vector.
  270. int10 label word
  271. ints ends
  272.  
  273.  
  274. ;
  275. ; Program segment.
  276. ;
  277.  
  278. zap segment
  279.  assume CS:zap,DS:zap,ES:zap,SS:zap
  280.  
  281. ;
  282. ; Put service code as low as DOS will allow.
  283.  org 5Ch
  284. time dw ?               ;Time before blanking in ticks.
  285. count dw ?              ;Tick countdown.
  286. trap label word         ;Location for interrupt traps.
  287.  
  288. ;
  289. ; Partially parsed command line.
  290.  org 5Ch
  291. f1 db 12 dup(?)
  292.  org 6Ch
  293. f2 db 12 dup(?)
  294.  
  295. ;
  296. ; Constants.
  297. DTIME equ 5462          ;Default time of about five minutes.
  298.  
  299. ;
  300. ; Start of .COM code - jump to installation.
  301.  org 100h
  302. start:
  303.   jmp cpyrt
  304.    db 13,'ZAP version 1.0  Copyright (C) 1988  Mark Adler',13,10
  305.    db 'All rights reserved.',13,10,'Z'-64
  306.  cpyrt:
  307.  ;
  308.         ; process arguments.
  309.   cld                   ;This stays in effect for the whole program.
  310.   mov onoff,1           ;Set ZAP to on.
  311.   mov id,'Z'            ;So we don't find COM file in a buffer.
  312.   mov BX,offset f1
  313.   call chknon           ;See if no arg.
  314.   je afin
  315.    call chkoff          ;Have first arg---see if on or off.
  316.    je do2
  317.     call chknum         ;Not on or off---see if number.
  318.     jz erra             ;If no number there, then bad args.
  319.   do2:
  320.    mov BX,offset f2
  321.    call chknon          ;See if second arg.
  322.    je afin
  323.     call chkoff         ;Have second arg---see if on or off.
  324.     je aok
  325.      call chknum        ;Not on or off---see if number.
  326.      jz erra            ;If no number there, then bad args.
  327.    aok:
  328.  afin:
  329.  
  330.         ; look to see if ZAP is installed yet.
  331.   mov DX,DS             ;Start checking backwards from this segment.
  332.   assume ES:nothing
  333.  search:
  334.    dec DX
  335.    jz nowhere           ;If at bottom of memory, then it ain't loaded.
  336.    mov SI,offset id     ;Point DS:SI to id string to look for.
  337.    mov ES,DX            ;Point ES:DI to where to look.
  338.    sub DI,DI            ;The id string should be on a 16 byte boundary.
  339.    mov CX,idlen
  340.    repe cmpsb
  341.    jne search           ;If no match, look one back.
  342.         ; now ES:DI point to byte after id.
  343.   mov AL,onoff          ;Set enable byte of ZAP.
  344.   stosb
  345.   add DI,16-(1+idlen+4) ;Point to time and count.
  346.   dec DX
  347.   mov ES,DX
  348.   mov AX,newtime        ;Get time setting.
  349.   test AX,AX            ;See if it is a new setting.
  350.   jnz usenew
  351.    mov AX,ES:[DI]       ;If no new setting, use old setting.
  352.  usenew:
  353.   stosw
  354.   stosw                 ;Reset count as well.
  355.   mov AH,0Fh            ;Turn display on in case it's off.
  356.   int 10h               ;(dummy int 10 call.)
  357.   int 20h               ;Done.
  358.  
  359.         ; ZAP not installed---install with specified options.
  360.  nowhere:
  361.   mov AX,DS             ;Restore ES.
  362.   mov ES,AX
  363.   assume ES:zap
  364.   mov AL,onoff          ;Get on/off setting.
  365.   mov enbl,AL           ;Put in enbl flag in traps before moving.
  366.   mov AX,newtime        ;Set time and count.
  367.   test AX,AX
  368.   jnz timok
  369.    mov AX,DTIME         ;Get default time (five minuntes).
  370.  timok:
  371.   mov time,AX
  372.   mov count,AX
  373.   jmp copy              ;Go set up traps and stay resident.
  374.  
  375. erra:
  376.   mov DX,offset err2
  377.   jmp short errx
  378.  
  379. chknon proc near
  380.   mov SI,BX
  381.   mov DI,offset snone
  382.   mov CX,6
  383.   repe cmpsw
  384.   ret
  385. chknon endp
  386.  
  387. chkoff proc near
  388.  ; Compare [BX] with soff and son, return NE if neither match.
  389.   mov SI,BX
  390.   mov DI,offset soff
  391.   mov CX,6
  392.   repe cmpsw
  393.   jne noff
  394.    mov onoff,0
  395.    ret
  396.  noff:
  397.   mov SI,BX
  398.   mov DI,offset son
  399.   mov CX,6
  400.   repe cmpsw
  401.   ret
  402. chkoff endp
  403.  
  404. chknum proc near
  405.   lea SI,[BX+1]         ;Point to arg (BX loaded already).
  406.   sub BX,BX             ;Initial value.
  407.   mov DI,10             ;Base for decimal.
  408.   mov CX,8              ;Digits allowed in name.
  409.  numlp:
  410.    lodsb
  411.    sub AL,'0'
  412.    jb nend
  413.    cmp AL,9
  414.    ja nend
  415.    cbw
  416.    xchg AX,BX
  417.    mul DI
  418.    add BX,AX
  419.    loop numlp
  420.  nend:
  421.   test BX,BX            ;See if got a value.
  422.   jz nret               ;If not, just return.
  423.    mov AX,91            ;Multiply by 18.2.
  424.    mul BX
  425.    shr DI,1             ;Put 5 in DI.
  426.    cmp DX,DI
  427.    jae errn             ;If number of seconds too high, then error.
  428.    div DI               ;18.2 = 91/5.
  429.    cmp DX,3             ;See if need to round up.
  430.    jb rdown             ;If remainder 0, 1, or 2, then round down.
  431.     inc AX              ;Else, round up.
  432.   rdown:
  433.    mov newtime,AX       ;(Note, Z flag is false here.)
  434.  nret:
  435.   ret                   ;Return NZ if got a valid time.
  436. chknum endp
  437.  
  438. errn:
  439.   mov DX,offset err1
  440. errx:
  441.   mov AH,9
  442.   int 21h
  443.   int 20h
  444.  
  445. err1 db '?Seconds out of range---must be in 1..3600',13,10,'$'
  446. err2 db '?Invalid argument---can be "on", "off", or time'
  447.      db 10,13,'$'
  448.  
  449. soff db 0,'OFF        '
  450. son db 0,'ON         '
  451. snone db 0,'           '
  452. newtime dw 0
  453. onoff db 1
  454.  
  455. ;
  456. ; Traps - only assume CS points here.
  457.   assume DS:nothing,ES:nothing,SS:nothing
  458. set:                    ;Traps.
  459.  
  460.  id db ' APTSR'
  461.  idlen equ $-id
  462.  enbl db 1              ;Enable flag.
  463.  
  464.  tick:
  465.   ;
  466.   ; Timer tick action - if tick count not at already at zero, decrement
  467.   ; it.  If this makes the count zero, blank the screen.
  468.   ;
  469.    cmp byte ptr trap+(enbl-set),1       ;See if enabled.
  470.    jne tfin             ;If not, skip this.
  471.    cmp count,0          ;See if count at zero.
  472.    je tfin              ;If so, don't decrement.
  473.     dec count           ;Decrement tick count.
  474.     jnz tfin            ;Wait until counts down to zero.
  475.         ; disable display.
  476.     ifdef EGA
  477.      egaoff
  478.     else
  479.      vgaoff
  480.     endif
  481.         ; go on to service routine.
  482.   tfin:
  483.    jmp dummy            ;Go on to service routine.
  484.   tvec equ $-4          ;Address in jmp.
  485.  
  486.  scan:
  487.   ;
  488.   ; Keyboard scan code action - reset the count to the maximum.  If the
  489.   ; count was zero, then the screen is blanked.  In that case, restore
  490.   ; the display.
  491.   ;
  492.    push AX
  493.    cmp count,0          ;See if count at zero.
  494.    jne sfin             ;If not, just reset count.
  495.     call don            ;Display blanked - restore it.
  496.   sfin:
  497.    mov AX,time
  498.    mov count,AX         ;Reset count.
  499.    pop AX
  500.    jmp dummy            ;Go on to service routine.
  501.   svec equ $-4          ;Address in jmp.
  502.  
  503.  vid:
  504.   ;
  505.   ; Video service request action - reset the count to the maximum.  If
  506.   ; the count was zero, then the screen is blanked.  In that case,
  507.   ; restore the display.
  508.   ;
  509.    push AX
  510.    cmp count,0          ;See if count at zero.
  511.    jne vfin             ;If not, just reset count.
  512.     call don            ;Display blanked - restore it.
  513.   vfin:
  514.    mov AX,time
  515.    mov count,AX         ;Reset count.
  516.    pop AX
  517.  altvid:                ;(For using Int 10h within these routines.)
  518.    jmp dummy            ;Go on to service routine.
  519.   vvec equ $-4          ;Address in jmp.
  520.  
  521.  
  522.  don:
  523.   ifdef EGA
  524.    egaon
  525.   else
  526.    vgaon
  527.   endif
  528.  
  529.  setlen equ $-set       ;End of traps.
  530.  
  531.  
  532. ;
  533. ; Installation code - all segment registers set.
  534.  assume DS:zap,ES:zap,SS:zap
  535.  
  536.  copy:
  537.   ;
  538.   ; Install traps and tell DOS to leave them in memory.
  539.   ;
  540.         ; copy traps to lower memory.
  541.    mov SI,offset set
  542.    mov DI,offset trap
  543.    mov CX,setlen
  544.    rep movsb            ;Assume direction flag cleared.
  545.         ; set up to insert traps into interrupt vectors.
  546.    sub AX,AX
  547.    mov ES,AX            ;Point to interrupt area.
  548.    assume ES:ints
  549.    cli                  ;Disable interrupts during change.
  550.         ; insert trap in timer tick interrupt vector.
  551.    mov AX,int8          ;Get old vector.
  552.    mov trap+(tvec-set),AX       ;Put in jump instruction.
  553.    mov AX,int8+2
  554.    mov trap+(tvec+2-set),AX
  555.    mov AX,offset trap+(tick-set)
  556.    mov int8,AX          ;Change Int 8 to the trap.
  557.    mov AX,CS
  558.    mov int8+2,AX
  559.         ; insert trap in keyboard scan code interrupt vector.
  560.    mov AX,int9          ;Get old vector.
  561.    mov trap+(svec-set),AX       ;Put in jump instruction.
  562.    mov AX,int9+2
  563.    mov trap+(svec+2-set),AX
  564.    mov AX,offset trap+(scan-set)
  565.    mov int9,AX          ;Change Int 9 to the trap.
  566.    mov AX,CS
  567.    mov int9+2,AX
  568.         ; insert trap in video service interrupt vector.
  569.    mov AX,int10         ;Get old vector.
  570.    mov trap+(vvec-set),AX       ;Put in jump instruction.
  571.    mov AX,int10+2
  572.    mov trap+(vvec+2-set),AX
  573.    mov AX,offset trap+(vid-set)
  574.    mov int10,AX         ;Change Int 10h to the trap.
  575.    mov AX,CS
  576.    mov int10+2,AX
  577.         ; tell DOS to keep the traps in memory and exit.
  578.    sti                  ;Interrupts OK now.
  579.    mov DX,offset trap+setlen    ;Amount to keep.
  580.    int 27h              ;Exit and remain resident.
  581.  
  582. zap ends
  583.  
  584. end start
  585.  
  586.